#include <stdio.h>
#include <stdbool.h>

#include <board.h>
#include <corepac.h>
#include "memspace.h"
#include "mcbl.h"


#if _BIG_ENDIAN
#define OPTION(A,B, C, D) ((uint32_t)(A<<24) | (B << 16) | (C << 8) | D)
#else
#define OPTION(D, C, B, A) ((uint32_t)(A<<24) | (B << 16) | (C << 8) | D)
#endif


#pragma CODE_SECTION(main, ".boot")
void main() {
    if (0 != DNUM)
        printf("----MCBL curing tool @SOC-%d---\n", Soc_getId());

    setup((CorePac)DNUM);

    if (0 != DNUM) goto LOAD;

	McblCfg cfg = {
       .image[COREPAC0] = DEF_UING(0),
       .image[COREPAC1] = DEF_UING(1),
       .image[COREPAC2] = DEF_UING(2),
       .image[COREPAC3] = DEF_UING(3),
       .image[COREPAC4] = DEF_UING(4),
       .image[COREPAC5] = DEF_UING(5),
       .image[COREPAC6] = DEF_UING(6),
       .image[COREPAC7] = DEF_UING(7),
       .image[ALL_CORES] = DEF_BASE_ING,
       .image[ALL_CORES + 1] = DEF_BL_IMG,
       .coreCnt = MCBL_CORE_CNT,
	   .smpMask = DFE_SMP_MASK,
	   .bootMode = BOOT_MODE_EMIF16,
       .uimgTotalSz = USR_CURING_SIZE,
       .bootloaderSz = BOOT_LOADER_SIZE,
       .curingBootloader = 0,
       .curingCoreApp = 0xFFFFFFFF
	};

	printf("default configurations:\n"
	       "\tBMOD - %d(%s)\n"
	       "\tBLSZ - %08x\n"
	       "\tCORE - %d\n"
	       "\tAPPL - %08x\n"
	       "\tSMPM - %08x\n"
           "\tBIMG - %s\n"
           "\tUIMG - %s~%d\n"
           "\tCUBL - %d\n"
           "\tCAPP - %08x\n",
	       /*BMOD - %d(%s)*/cfg.bootMode, "BOOT_MODE_EMIF16",
	       /*BLSZ - 0x%x*/cfg.bootloaderSz,
	       /*CORE - %d*/cfg.coreCnt,
	       /*APPL - 0x%x*/cfg.uimgTotalSz,
	       /*SMPM - %08x*/cfg.smpMask,
	       /*BIMG - %s"*/&cfg.image[cfg.coreCnt][0],
           /*UIMG - %s~%d"*/&cfg.image[0][0], cfg.coreCnt - 1,
           /*CUBL - %%c*/cfg.curingBootloader,
           /*CAPP - %08x*/cfg.curingCoreApp );

	printf("reading %s as configuration script...\n", FCFG);
	FILE* fcfg = fopen(FCFG, "ro");
	if (NULL == fcfg) {
	    printf("\t cannot open configuration file - %s, fix & try later.\n", FCFG);
	    errHang();
	}


        #define OPT_LINE_SZ 256
        #define COMMENT_FLAG    '#'
        #define COMMENT_FLAG_   '/'
        #define EMPTY_LINE      '\n'
	printf("parsing configuration script....\n");

	union {
	    struct {
	        char characters[OPT_LINE_SZ];
	    } comment;
	    struct {
	        union {
	            uint32_t val;
                char     description[4];
	        }    option;
	        char eq;
	        char content[OPT_LINE_SZ];
	    } cfg;
	}        cfgLine;
    uint32_t dval;
    uint32_t xval;
	char*    c = &cfgLine.cfg.option.description[0];
	char*    sval = &cfgLine.cfg.content[0];

	while (NULL != fgets((char*)&cfgLine, sizeof(cfgLine), fcfg)) {
	    char flg = cfgLine.comment.characters[0];
	    if ((flg == COMMENT_FLAG) || (flg == COMMENT_FLAG_) || (flg == EMPTY_LINE)) {
	        continue; }
	    if (cfgLine.cfg.eq != '=') {
	        printf("invalid configuration file!\n");
	        errHang();
	    }

        sscanf(sval, "%d", &dval);
        sscanf(sval, "0x%d", &xval);
        switch (cfgLine.cfg.option.val) {
        case OPTION('B','M','O','D'):
            cfg.bootMode = dval;
            printf("\tBMOD - %d\n", dval);
            break;

        case OPTION('B','L','S','Z'):
            cfg.bootloaderSz = xval;
            printf("\tBLSZ - %08x\n", xval);
            break;

        case OPTION('C','O','R','E'):
            cfg.coreCnt = dval;
            printf("\tCORE - %d\n", dval);
            break;

        case OPTION('A','P','P','L'):
            cfg.uimgTotalSz = xval;
            printf("\tAPPL - %08x\n", xval);
            break;

        case OPTION('S','M','P','M'):
            cfg.smpMask = xval;
            printf("\tSMPM - %08x\n", xval);
            break;

        case OPTION('C','U','B','L'):
            cfg.curingBootloader = dval;
            printf("\tCUBL - %d\n", dval);
            break;

        case OPTION('C','A','P','P'):
            cfg.curingCoreApp = xval;
            printf("\tCAPP - %08x\n", xval);
            break;

        case OPTION('U','I','M','G'):
        case OPTION('B','I','M','G'):
            printf("unsupported configuration %c%c%c%c", *c, *(c+1), *(c+2), *(c+3));
            break;

        default:
        printf("unknown configuration option %c%c%c%c", *c, *(c+1), *(c+2), *(c+3));
        }
	}
	fclose(fcfg);


	if (cfg.smpMask != NONE) {
	    cfg.curingCoreApp |= (FLG << ALL_CORES); }
    curing(&cfg);

    static bool loadApp = true;
    printf("curing pass! %s\n", loadApp ? "load cores' images." : "");

LOAD:
    if (loadApp)
        load((McblImgDesc*) MCBL_TLB_BASE);
}


